package com.sneakxy.mybatis.commons.dialect;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.session.Configuration;
import org.springframework.data.domain.Pageable;

/**
 * 分页方言
 * @author DEVILIVED
 *
 */
public abstract class Dialect {
	
	public static final String DOT = ".";

	private Configuration configuration;
	
	public Dialect(Configuration configuration) {
		this.configuration = configuration;
	}
	
	/**
	 * 格式化分页语句
	 * @param sql 未分页SQL语句
	 * @param parameterValues 参数Map
	 * @param page 分页信息
	 * @param params 参数列表
	 * @return sql语句
	 */
	public String process(String sql, Map<String, Object> parameterValues, Pageable page, List<ParameterMapping> params) {
		if(this.isProcessed(sql, parameterValues, page)) {
			return sql;
		}
		this.setParameterValues(parameterValues, page);
		ProcessHandler handler = this.onProcess(sql, parameterValues, page);
		this.addParameterMappings(params, handler);
		return handler.getSql();
	}
	
	private void addParameterMappings(List<ParameterMapping> params, ProcessHandler handler) {
		params.addAll(handler.getParams());
	}

	protected abstract ProcessHandler onProcess(String sql, Map<String, Object> parameterValues, Pageable page);
	
	/**
	 * 判断是否需要分页
	 * @param sql 未分页SQL语句
	 * @param parameterValues 参数Map
	 * @param page 分页信息
	 * @return 是否需要
	 */
	protected abstract boolean isProcessed(String sql, Map<String, Object> parameterValues, Pageable page);
	
	/**
	 * 添加分页信息到参数
	 * @param parameterValues
	 * @param page
	 */
	protected abstract void setParameterValues(Map<String, Object> parameterValues, Pageable page);
	
	public abstract String upperFunction(String column);
	
	/**
	 * 构建正则判断SQL语句
	 * @param column
	 * @param value
	 * @return 正则判断SQL语句
	 */
	public abstract String buildRegexSql(String column, String value);

	/**
	 * 序列自增ID策略,是否需要字段
	 * @return 是否需要
	 */
	public abstract boolean needSequenceIdColumnSql();
	
	/**
	 * 格式化列名
	 * @param columnName 未格式化列名
	 * @return 格式化后列名
	 */
	public String formatColumnName(String columnName) {
		if(StringUtils.contains(columnName, DOT)) {
			return StringUtils.join(
					Arrays.stream(StringUtils.split(columnName, DOT))
						.map(column -> formatSimpleColumnName(column)).toList(), DOT);
		}
		return formatSimpleColumnName(columnName);
	}
	
	/**
	 * 格式化简单列名
	 * @param columnName 未格式化列名
	 * @return 格式化后列名
	 */
	protected String formatSimpleColumnName(String columnName) {
		return columnName;
	}
	
	/**
	 * 序列自增ID策略,字段值
	 * @param generator
	 * @return 需要填的替换字段值得语句
	 */
	public abstract String getSequenceIdColumnValue(String generator);
	
	/**
	 * 获取新增ID值的sql语句
	 * @param generator
	 * @param idColumn
	 * @return 查询新的字段值语句
	 */
	public abstract String getSequenceIdSql(String generator, String idColumn);
	
	protected Configuration getConfiguration() {
		return configuration;
	}

	public static class ProcessHandler {
		
		public String sql;
		
		private List<ParameterMapping> params;
		
		public ProcessHandler(String sql, List<ParameterMapping> params) {
			this.sql = sql;
			this.params = params;
		}

		public String getSql() {
			return sql;
		}

		public List<ParameterMapping> getParams() {
			return params;
		}
		
	}
}
